package com.retailcloud.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.retailcloud.gateway.config.JwtProperties;
import com.retailcloud.gateway.constant.LoginTypeEnum;
import com.retailcloud.gateway.constant.TenantStatusEnum;
import com.retailcloud.gateway.constant.UserRoleEnum;
import com.retailcloud.gateway.dto.TenantsDTO;
import com.retailcloud.gateway.dto.UserDTO;
import com.retailcloud.gateway.utils.EnumValidationUtils;
import com.retailcloud.gateway.utils.RedisUtils;
import io.jsonwebtoken.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.List;

@Component
public class TokenAuthenticationFilter extends AbstractGatewayFilterFactory<TokenAuthenticationFilter.Config> {

    private static final Logger logger = LoggerFactory.getLogger(TokenAuthenticationFilter.class);

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private JwtProperties jwtProperties;

    public TokenAuthenticationFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            String requestPath = request.getURI().getPath();

            // 添加日志输出
            logger.info("TokenAuthenticationFilter applied for path: {}", requestPath);

            // 检查是否在忽略路径列表中
            List<String> ignorePaths = jwtProperties.getIgnorePaths();
            if (ignorePaths.stream().anyMatch(requestPath::startsWith)) {
                return chain.filter(exchange);
            }
            String token = request.getHeaders().getFirst("Authorization");
            //loginType: wechat、pc
            String loginType = request.getHeaders().getFirst("loginType");
            //校验登录方式
            if(!EnumValidationUtils.isValueInEnum(loginType, LoginTypeEnum.class)) {
                return loginTypeResponse(response);
            }
            if (token == null || !token.startsWith("Bearer ")) {
                return unauthorizedResponse(response);
            }
            token = token.substring(7); // 去掉 "Bearer "
            try {
                Claims claims = Jwts.parser().setSigningKey(jwtProperties.getSecret()).parseClaimsJws(token).getBody();
                String username = claims.getSubject();
                String tokenUserInfo = redisUtils.get("tokenUserInfo:" + username);

                if (StringUtils.isNotBlank(tokenUserInfo)) {
                    UserDTO userDTO = JSONObject.parseObject(tokenUserInfo, UserDTO.class);
                    if (loginType.equals(LoginTypeEnum.wechat)) {
                        //判断用户类型，针对小程序端
                        if (userDTO.getRole().equals(UserRoleEnum.企业管理员) || userDTO.getRole().equals(UserRoleEnum.普通用户)) {
                            if (username == null || username.isEmpty()) {
                                return unauthorizedResponse(response);
                            }
                            // 检查 token 是否存在于 Redis 中
                            String storedToken = redisUtils.get("wechatToken:" + username);
                            if (storedToken == null || !storedToken.equals(token)) {
                                return unauthorizedResponse(response);
                            }
                            if (StringUtils.isBlank(userDTO.getTenantId()) ) {
                                return initTenantResponse(response);
                            }
                            TenantsDTO tenants = userDTO.getTenantsDTO();
                            if (tenants != null) {
                                if (tenants.getStatus().equals(TenantStatusEnum.待审核)) {
                                    return auditTenantResponse(response);
                                }
                            }
                        }
                    }
                }
                // 将用户名添加到请求头中，以便下游服务使用
                request = request.mutate().header("X-User-Name", username).build();
                exchange = exchange.mutate().request(request).build();

            } catch (ExpiredJwtException | MalformedJwtException | SignatureException e) {
                return unauthorizedResponse(response);
            }
            return chain.filter(exchange);
        };
    }

    private Mono<Void> auditTenantResponse(ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json");
        DataBufferFactory bufferFactory = response.bufferFactory();
        DataBuffer buffer = bufferFactory.wrap("{\"msg\":\"企业信息正在审核中，请耐心等待工作人员审核!\",\"code\":4003,\"data\":\"\"}".getBytes());
        return response.writeWith(Mono.just(buffer));
    }

    private Mono<Void> loginTypeResponse(ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json");
        DataBufferFactory bufferFactory = response.bufferFactory();
        DataBuffer buffer = bufferFactory.wrap("{\"msg\":\"登录方式不合法!\",\"code\":4004,\"data\":\"\"}".getBytes());
        return response.writeWith(Mono.just(buffer));
    }

    private Mono<Void> initTenantResponse(ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json");
        DataBufferFactory bufferFactory = response.bufferFactory();
        DataBuffer buffer = bufferFactory.wrap("{\"msg\":\"用户还没有注册企业信息，请先注册企业信息!\",\"code\":4002,\"data\":\"\"}".getBytes());
        return response.writeWith(Mono.just(buffer));
    }

    private Mono<Void> unauthorizedResponse(ServerHttpResponse response) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json");
        DataBufferFactory bufferFactory = response.bufferFactory();
        DataBuffer buffer = bufferFactory.wrap("{\"msg\":\"token无效或者已经过期，需要重新登录!\",\"code\":4001,\"data\":\"\"}".getBytes());
        return response.writeWith(Mono.just(buffer));
    }

    public static class Config {
        // 配置类，目前没有配置项
        public static final Config instance = new Config();
    }
}
